package com.firebird.app.kotlin.stock.trend.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Handler
import android.widget.ImageView
import java.io.*
import java.net.HttpURLConnection
import java.net.MalformedURLException
import java.net.URL
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


/**
 * 异步图片加载工具类
 * 使用文件缓存时，需要用到SD卡读写权限
 * @author ljk
 * @date   2019年11月12日
 */
class AsyncImageLoader(context: Context?, threads: Int) {
    private var memoryCache: MemoryCache?=null
    private val fileCache: FileCache
    private val executorService: ExecutorService
    private val handler = Handler() //handler to display images in UI thread
    private val imageViews = Collections.synchronizedMap(WeakHashMap<ImageView, String>())
    /**
     * 显示网络图片
     * @param imgUrl
     * @param imageView
     */
    fun DisplayImage(imgUrl: String, imageView: ImageView) {
        imageViews[imageView] = imgUrl
        // 先从内存缓存中查找
        val bitmap: Bitmap = memoryCache!!.getBitmap(imgUrl)!!
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap)
        } else { //内存中没有图片，则开启线程加载图片
            queueImage(imgUrl, imageView)
            imageView.setBackgroundColor(Color.WHITE) //先设置为默认图片
        }
    }

    private fun queueImage(imgUrl: String, imageView: ImageView) {
        val task = ImageLoadTask(imgUrl, imageView)
        executorService.submit(ImageLoader(task))
    }

    /**
     * 线程队列中的Task
     * @author ljk
     * @date   2019年11月12日
     */
    private inner class ImageLoadTask(var imageUrl: String, var imageView: ImageView)

    private inner class ImageLoader(private val task: ImageLoadTask) : Runnable {
        override fun run() {
            if (imageViewReused(task)) {
                return
            }
            val bitmap = getBitmap(task.imageUrl)
            memoryCache?.put(task.imageUrl, bitmap)
            if (imageViewReused(task)) {
                return
            }
            val bd = BitmapDisplayer(bitmap, task)
            handler.post(bd)
        }

    }

    /**
     * 防止图片错位
     * @param task
     * @return
     */
    private fun imageViewReused(task: ImageLoadTask): Boolean {
        val tag = imageViews[task.imageView]
        return if (tag != null && tag != task.imageUrl) {
            true
        } else false
    }

    private fun getBitmap(imgUrl: String): Bitmap? { //先从文件缓存中查找是否有相应的图片，如果有则返回
        val file: File = fileCache.getFile(imgUrl)
        val fileBitmap = decodeFile(file)
        if (fileBitmap != null) {
            return fileBitmap
        }
        try {
            var bitmap: Bitmap? = null
            val imageUrl = URL(imgUrl)
            val conn = imageUrl.openConnection() as HttpURLConnection
            conn.connectTimeout = 30000
            conn.readTimeout = 30000
            conn.instanceFollowRedirects = true
            val `is` = conn.inputStream
            val os: OutputStream = FileOutputStream(file)
            val buffer_size = 1024
            val bytes = ByteArray(buffer_size)
            while (true) {
                val count = `is`.read(bytes, 0, buffer_size)
                if (count == -1) break
                os.write(bytes, 0, count)
            }
            os.close()
            conn.disconnect()
            bitmap = decodeFile(file)
            return bitmap
        } catch (e: MalformedURLException) {
            e.printStackTrace()
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * decode这个图片并且按比例缩放以减少内存消耗，虚拟机对每张图片的缓存大小也是有限制的
     * @param file
     * @return
     */
    private fun decodeFile(file: File): Bitmap? {
        try { //decode image size
            val opts = BitmapFactory.Options()
            opts.inJustDecodeBounds = true
            val fis = FileInputStream(file)
            BitmapFactory.decodeStream(fis, null, opts)
            fis.close()
            val REQUIRED_SIZE = 70
            var width_tmp = opts.outWidth
            var height_tmp = opts.outHeight
            var scale = 1
            while (true) {
                if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) break
                width_tmp /= 2
                height_tmp /= 2
                scale *= 2
            }
            //decode with inSampleSize
            val o2 = BitmapFactory.Options()
            o2.inSampleSize = scale
            val stream2 = FileInputStream(file)
            val bitmap = BitmapFactory.decodeStream(stream2, null, o2)
            stream2.close()
            return bitmap
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 用于在UI线程中更新界面
     * @author ljk
     * @date   2019年11月12日
     */
    private inner class BitmapDisplayer(private val bitmap: Bitmap?, private val task: ImageLoadTask) : Runnable {
        override fun run() {
            if (imageViewReused(task)) {
                return
            }
            if (bitmap != null) {
                task.imageView.setImageBitmap(bitmap)
            } else {
                task.imageView.setBackgroundColor(Color.WHITE)
            }
        }

    }

    /**
     * 同时清除 内存缓存和文件缓存
     */
    fun clearCache() {
        memoryCache?.clear()
        fileCache.clear()
    }

    /**
     * 清理内存缓存
     */
    fun clearMemoryCache() {
        memoryCache?.clear()
    }

    /**
     * 清理文件缓存
     */
    fun clearFileCache() {
        fileCache.clear()
    }

    /**
     * @param context    android 上下文对象
     * @param threads    线程池中启动的线程数
     */
    init {
        memoryCache = MemoryCache()
        fileCache = FileCache(context!!)
        executorService = Executors.newFixedThreadPool(threads)
    }
}


